﻿/**************************************************************************
* 文件名称: comMacro.h
* 文件标识:
* 内容摘要: 自定义的一些通用的宏, 非常实用, 用于常见的代码片段。可通用于所有项目。
* 用宏可以让编译器预先计算一些数值，或者自动生成合适的代码，提高代码的灵活性和执行效率
* 其它说明:
* 当前版本: V3.0
* 作   者: 李荣业
* 完成日期: 2015-11-25 19:34:20
* 修改记录1:
*     修改日期:
*     版 本 号:
*     修 改 人:
*     修改内容:
**************************************************************************/

#ifndef __COM_MACRO_H__
#define __COM_MACRO_H__

/// 跨平台宏定义，支持不同平台条件编译
#if defined(_WIN32)
#    define LINE_SEPARATOR "\r\n" // Windows风格的换行符
#elif defined(__linux)
#    define LINE_SEPARATOR "\n" // Linux风格的换行符
#else
#    define LINE_SEPARATOR "\n" // UNIX风格的换行符
#endif

#ifdef _MSC_VER
#    define typeof decltype
#endif

#define STR(arg)      STR1(arg)
#define STR1(arg)     STR2(arg)
#define STR2(arg)     #arg

// 获取数组长度
#define ARRAY_LEN(a) (int)(sizeof(a) / sizeof(a[0]))

// 判断 index 是否为 数组 array 的有效索引
#define VALID_ARRAY_INDEX(index, array) ((index) >= 0 && (index) < (typeof(index))ARRAY_LEN(array))

// 用于 for 循环遍历数组，简化代码编写
#if 1   // C99才支持
#define FOR_LOOP_ARRAY(i, array)     for(int i = 0; i < ARRAY_LEN(array); ++i)
#else   // 低于C99的版本使用这个
#define FOR_LOOP_ARRAY(i, array)     int i; for(i = 0; i < ARRAY_LEN(array); ++i)
#endif

// 获取一个变量的首地址及其字节数, 转换成 void * 类型
#define STR_MEM_ARGS(str) (str), STRLEN(str)
#define VAR_MEM_ARGS(var) &(var), sizeof(var)

// 获取一个变量的首地址及其字节数, 转换成 char * 类型
#define VAR_MEM_ARGS_CHAR(var) (char *)&(var), sizeof(var)
#define VAR_MEM_ARGS_CONST_CHAR(var) (const char *)&(var), sizeof(var)

// 获取一个数组的首地址及其元素个数, 转换成 数组元素 * 类型
#define ARRAY_MEM_ARGS(array) (array), ARRAY_LEN(array)

// 对变量清零
#define RESET_VAR(var) memset(&(var), 0x00, sizeof(var))
#define RESET_PTR_VAR(p) memset(p, 0x00, sizeof(*(p)))
#define RESET_MEM(p, size) memset(p, 0x00, size)

#define MEMSET(pDst, val, size)     memset(pDst, (int)(val), (size_t)(size))
#define MEMSET2ARR(array, val)      MEMSET(&(array), val, sizeof(array))

#define MEMCPY(pDst, pSrc, size)    memcpy(pDst), pSrc, (size_t)(size))
#define MEMCPY2ARR(array, pSrc)     MEMCPY(&(array), pSrc, sizeof(array))

#define MEMMOVE(pDst, pSrc, size)   memmove(pDst, pSrc, (size_t)(size))
#define MEMMOVE2ARR(array, pSrc)    MEMMOVE(&(array), pSrc, sizeof(array))

#define MEMCMP(p1, p2, size)        memcmp(p1, p2, (size_t)(size))
#define MEMCMP_OF_ARR(array, pSrc)  MEMCMP(&(array), pSrc, sizeof(array))

#define STRCPY_S(pDst, size, pSrc)  strcpy_s((char *)(pDst), (size_t)(size), (const char *)(pSrc))
#define STRCPY2ARR(array, pSrc)     STRCPY_S(&(array), sizeof(array), pSrc)
#define STRCPY_FROM_ARR(pDest, array)   STRCPY_S(pDest, sizeof(array), &(array))

#define STRCAT(pDst, pSrc)          strcat((char *)(pDst), (const char *)(pSrc))
#define STRNCAT(pDst, pSrc, size)   strncat((char *)(pDst), (const char *)(pSrc), (size_t)(size))

#define STRNCMP(pDst, pSrc, size)   strncmp((const char *)(pDst), (const char *)(pSrc), (size_t)(size))
#define STRNCMP_OF_ARR(array, pSrc) STRNCMP(&(array), pSrc, sizeof(array))
#define CSTR_IS_EQUAL(pDst, pSrc)   (0 == STRNCMP_OF_ARR(pDst, pSrc))
#define CSTR_NOT_EQUAL(pDst, pSrc)  (0 != STRNCMP_OF_ARR(pDst, pSrc))

#define STRPRI2ARR(array, format, ...)  snprintf((char *)&(array), sizeof(array), format, ##__VA_ARGS__)

// 计算字符串常量的长度。由于 sizeof 是在编译期间计算完成的，所以比strlen效率高。
// str必须是字符串常量，不可以为指针变量。用法如 int len = STRLEN("Hello world");
#define STRLEN(str)             (sizeof(str) - 1)
#define STRLEN_OF_ARR(array)    strnlen((const char *)(&(array)), sizeof(array))

#define CLEAR_STR(str)          (str)[0] = '\0'
#define IS_NULL_STR(str)        ('\0' == (str)[0])
#define IS_NOT_NULL_STR(str)    ('\0' != (str)[0])
#define IS_VALID_HANDLE(handle) ( (unsigned long)NULL != (handle) && SI_INVALID_HANDLE != (handle) )

#define NUM_OF_BITS(var) (8 * sizeof(var))  // 计算变量的位(bit)的个数

// 获取变量var的第 byteIndex 个字节的值, byteIndex 从1开始计算
#define BYTE_OF_VAR(var, byteIndex) (((var) >> (8 * ((byteIndex)-1))) & 0xFF)

// 获取变量var的 startBit 位开始的 bitCount 个位的值, startBit 从第0位开始计算
#define BITS_OF_VAR(var, startBit, bitCount) (((var) >> (startBit)) & BIT_SET_1(bitCount))

// 获取指针 p 指向的内存地址开始的第 bitIndex 个位的值(0或1), bitIndex 从第0位开始计算
#define BIT_VALUE_ADDR(p, bitIndex)  ( ( *((const char *)(p)+(bitIndex)/8) >> (bitIndex)%8 ) & 1 )

// 获取变量 var 的第 bitIndex 个位的值(0或1), bitIndex 从第0位开始计算
#define BIT_VALUE(var, bitIndex)  ( ((var) >> (bitIndex)) & 1 )

// 将低 bitCount 个位置1, bit 从第0位开始计算
#define BIT_SET_1(bitCount)      ( (1 << (bitCount)) - 1 )

/* 设置位, bitIndex 从第0位开始计算 */
#define SET_BIT(var, bitIndex)     var |= (1 << (bitIndex))

/* 清除位, bitIndex 从第0位开始计算 */
#define CLEAR_BIT(var, bitIndex)   var &= (~(1 << (bitIndex)))


/* 取最小值 */
#define LIMIT_MIN(value, min)   value = ( (value) < (min) ? (min) : (value) )

/* 取最大值 */
#define LIMIT_MAX(value, max)   value = ( (value) < (max) ? (max) : (value) )

#ifndef MIN
template <typename T> inline const T & MIN(const T & a, const T & b) { return a < b ? a : b; }
#endif

#ifndef MAX
template <typename T> inline const T & MAX(const T & a, const T & b) { return a > b ? a : b; }
#endif

/* 三个数取最大值 */
template <typename T> inline const T & MAX(const T & a, const T & b, const T & c) { return a > b ? (a > c ? a : c) : (b > c ? b : c); }
template <typename T> inline const T & MIN(const T & a, const T & b, const T & c) { return a < b ? (a < c ? a : c) : (b < c ? b : c); }

// 类型强制转换运算操作。将 oldTypeVar 强制转换成 destTypeVar 的类型，并且二者按照 opera 运算符进行运算
#define CAST_OPERATE(destTypeVar, opera, oldTypeVar)    ( (destTypeVar) opera (typeof(destTypeVar))(oldTypeVar) )

// 类型强制转换赋值操作。此宏我用得非常多。将 rightValue 的值赋给 leftValue, 如果类型不同则强制转换成 leftValue 的类型
#define CAST_ASSIGN(leftValue, rightValue)   CAST_OPERATE(leftValue, =, rightValue)

// 低级二进制强制拷贝赋值，作用类似 memcpy
#define BIN_ASSIGN(leftValue, rightValue)   (leftValue) = *(const typeof(leftValue) *)(&rightValue)

#define DEFINE_VAR_INIT(type, var, initValue)  typeof(type) (var) = (typeof(var))(initValue)
#define DEFINE_VAR_INIT_FROM_ADDR(type, var, pAddr)  typeof(type) (var) = *(const typeof(var) *)(pAddr)
#define TYPE_VALUE_OF_ADDR(type, pAddr)   ( *(typeof(type) *)(pAddr) )
#define READ_VAR_FROM_ADDR(var, pAddr)   (var) = *(const typeof(var) *)(pAddr)

// 从地址 pAddr 中读取 一个 var 类型的变量，并赋给 var，然后地址按照 var 的字节数自增
// 解析报文的时候很实用
#define READ_VAR_FROM_ADD_SELF_ADDR(var, pAddr)     \
    READ_VAR_FROM_ADDR(var, pAddr);  \
    CAST_ASSIGN(pAddr, (char *)(pAddr) + sizeof(var))

#define WRITE_VAR_TO_ADDR(var, pAddr)   *(typeof(var) *)(pAddr) = (var)

// 把 var 写入到地址 pAddr 中，然后地址按照 var 的字节数自增, 封装报文的时候很实用
#define WRITE_VAR_TO_ADD_SELF_ADDR(var, pAddr)     \
    WRITE_VAR_TO_ADDR(var, pAddr);  \
    CAST_ASSIGN(pAddr, (char *)(pAddr) + sizeof(var))

#define NAMESPACE_BEGIN(nameSpace)  \
    namespace nameSpace \
    {

#define NAMESPACE_END(nameSpace)   }

/*
 * swap - swap value of @a and @b
 */
#define SWAP_VALUE(a, b) \
    do { typeof(a) __LRY_tmp = (a); (a) = (b); (b) = __LRY_tmp; } while (0)

#define TO_BCD(val)     ((((val)/10)<<4) + (((val)%10)&0x0F))
#define FROM_BCD(val)   (((val)>>4)*10 + ((val)&0x0F))

#define GET_MEMBER_SIZE(typeOrVar, member)      sizeof( ((typeof(typeOrVar) *)0)->member )
#define GET_MEMBER_TYPE(typeOrVar, member)      typeof( ((typeof(typeOrVar) *)0)->member )
#define GET_MEMBER_ARRAY_LEN(type, member)      ARRAY_LEN(((typeof(type) *)0)->member)

// 获取结构体成员的偏移量。也适用于C++类对象。
// 一般编译器已内置此宏，但这个宏的 type 也可以是变量名，可以根据变量名自动探测结构体类型。
// 编译器内置的宏type则只能是结构体类型名。这里加上下划线 "_" 区分编译器内置的 offsetof 宏
#ifndef offset_of
#   define offset_of(type, member)  ((size_t)&((type *)0)->member)
#endif

// 获取结构体成员到末尾的偏移量，包括成员自身。也适用于C++类对象。
#define OFFSET_TO_END_OF_MEMBER(type, member)   (sizeof(type) - offset_of(type, member))

// 获取结构体成员后面还有多少个字节到末尾，不包括成员自身。也适用于C++类对象。
#define FRONT_SIZE_OF_MEMBER(type, member)      (OFFSET_TO_END_OF_MEMBER(type, member) - GET_MEMBER_SIZE(type, member))

// 大名鼎鼎的 container_of 宏。根据结构体的成员的地址找到结构体的地址, Linux内核中很常见。也适用于C++类对象。
#define container_of(ptr, type, member)     ( (type *)((char *)(ptr) - offset_of(type, member)) )

/**
* Check at compile time that something is of a particular type.
* Always evaluates to 1 so you may use it easily in comparisons.
*/
#define typecheck(type, x)   \
    ({ type __dummy;    \
        typeof(x) __dummy2; \
        (void)(&__dummy == &__dummy2);  \
        1;  \
    })

#define CHAR_2_NUM(ch)      ((ch) - '0')
#define NUM_2_CHAR(num)     ((num) + '0')
#define IS_NUM(num)         ((num) >= '0' && (num) <= '9')
#define IS_LETTER(num)      ( ((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') )


// 返回一个比m大的最接近的n的倍数
#define RND(m, n)       ( ((m) + (n) - 1) / (n) * n )
#define FAST_MOD(m, n)  ((m) & ((n) - 1))   // 快速取模, 速度比%快多了, 相当于取模m % n, n 必须是2的幂次方

// 将一个字母转换为大/小写
#define  UP_CASE(c) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )
#define  LOWER_CASE(c) ( ((c) >= 'A' && (c) <= 'Z') ? ((c) + 0x20) : (c) )

// 防止溢出的一个方法
#define  INC_SAT(val)  (val = ((val)+1 > (val)) ? (val)+1 : (val))

#define MIN_COUNT(hour, min)  ((hour) * 60 + (min))
#define SEC_COUNT(hour, min, sec)  (MIN_COUNT(hour, min) * 60 + (sec))

// 根据被动响应方的包的cmd，获得主动发送方的包的cmd。在CProtocol_XXXX.cpp文件中有用到
#define B_CMD_TO_A_CMD(cmd)     case cmd##_B: return cmd##_A
#define BA_CMD_TO_A_CMD(cmd)    case cmd##_BA: return cmd##_A
#define CASE_A_RETURN_B(val1, val2)     case val1: return val2

#define CASE_OTHER_NAME_2_OWN_NAME(nameSpace, name)     case nameSpace::name:   return name
#define CASE_OWN_NAME_2_OTHER_NAME(nameSpace, name)     case name:   return nameSpace::name

#define CASE_ENUM_2_TEXT_RETURN(value)      case (value): return STR(value)
#define CASE_ENUM_RETURN_STR(value, str)    case (value): return STR(str)


#if defined(__cplusplus) || defined(c_plusplus)

template <int n>
struct SConstFactorial
{
    enum { ret = n * SConstFactorial < n - 1 >::ret };
};

template <>
struct SConstFactorial<0>
{
    enum { ret = 1 };
};
// 求常数的阶乘，如 5!，n必须为常量
#define CONST_FACTORIAL(n)      (SConstFactorial<(n)>::ret)

template <unsigned int n, unsigned int m>
struct SConstPow
{
    enum { ret = n * SConstPow < n, m - 1 >::ret };
};

template <unsigned int n>
struct SConstPow<n, 0>
{
    enum { ret = 1 };
};

// 求常数n的m次方，如 2的3次方，n和m必须为常量
#define CONST_POW(n, m)      (SConstPow<(n), (m)>::ret)


// 极端强大的宏: 获取类成员函数地址，支持多态，即多态的虚函数会获取指针指向类型的虚函数入口地址
#define GET_VIRTUAL_FUNC_ADDR(pObj, className, funcName)    (pObj->*(&className::funcName))

#endif

#if 0
template<typename T>
inline T my_abs(T v) { return v >= 0 ? v : -v; }

/// \brief 判断浮点数是否相等
inline bool isEqual(double a, double b) { return my_abs(a - b) <= 1e-6; }

/// \brief 判断浮点数是否为0
inline bool is0(double a) { return my_abs(a) <= 1e-6; }
#endif

#endif  // __COM_MACRO_H__
